{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "c9bea21a-2a4e-4fb0-9081-d6692a0f736a",
   "metadata": {},
   "source": [
    "## **Python `requests` 库详解**\n",
    "\n",
    "### **课程目标**\n",
    "\n",
    "- 学习如何使用 `requests` 库发送 HTTP 请求\n",
    "- 理解 GET 和 POST 请求的区别\n",
    "- 学习如何处理响应数据\n",
    "- 学会发送带参数的请求、文件上传和处理异常\n",
    "\n",
    "---\n",
    "\n",
    "### **1. `requests` 库简介**\n",
    "\n",
    "- `requests` 是一个用于简化 HTTP 请求的 Python 库，使发送网络请求更容易。\n",
    "\n",
    "- 安装：\n",
    "\n",
    "  ```bash\n",
    "  pip install requests\n",
    "  ```\n",
    "\n",
    "### **2. HTTP 协议简介**\n",
    "\n",
    "- HTTP 是一种用于通信的协议。常见的请求方法包括：\n",
    "  - **GET**：获取资源\n",
    "  - **POST**：向服务器提交数据\n",
    "  - **PUT**：更新资源\n",
    "  - **DELETE**：删除资源\n",
    "\n",
    "---\n",
    "\n",
    "### **3. GET 请求**\n",
    "\n",
    "GET 请求用于从服务器获取数据。`httpbin` 提供了测试 GET 请求的接口。\n",
    "\n",
    "#### 示例代码："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "90042d3a-a0a5-4276-a36c-4dc379b50212",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-09-08T14:51:59.270205Z",
     "start_time": "2024-09-08T14:51:58.119463Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "状态码: 200\n",
      "响应内容: {\n",
      "  \"args\": {}, \n",
      "  \"headers\": {\n",
      "    \"Accept\": \"*/*\", \n",
      "    \"Accept-Encoding\": \"gzip, deflate, br, zstd\", \n",
      "    \"Host\": \"httpbin.org\", \n",
      "    \"User-Agent\": \"python-requests/2.32.2\", \n",
      "    \"X-Amzn-Trace-Id\": \"Root=1-66ddba0f-79b763ec262109c4685d1494\"\n",
      "  }, \n",
      "  \"origin\": \"221.15.159.55\", \n",
      "  \"url\": \"https://httpbin.org/get\"\n",
      "}\n",
      "\n",
      "解析后的 JSON 数据: {'args': {}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate, br, zstd', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.32.2', 'X-Amzn-Trace-Id': 'Root=1-66ddba0f-79b763ec262109c4685d1494'}, 'origin': '221.15.159.55', 'url': 'https://httpbin.org/get'}\n"
     ]
    }
   ],
   "source": [
    "import requests\n",
    "\n",
    "# 向 httpbin 发送 GET 请求\n",
    "response = requests.get('https://httpbin.org/get')\n",
    "\n",
    "# 打印状态码，状态码为 200 表示请求成功\n",
    "print(f'状态码: {response.status_code}')\n",
    "\n",
    "# 打印响应内容（文本格式）\n",
    "print(f'响应内容: {response.text}')\n",
    "\n",
    "# 如果服务器返回 JSON，可以使用 .json() 解析为字典\n",
    "data = response.json()\n",
    "print(f'解析后的 JSON 数据: {data}')\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4c9d0d9b-4cdc-46fa-ab4b-9566c4362f42",
   "metadata": {},
   "source": [
    "#### 讲解：\n",
    "\n",
    "1. `requests.get()` 用于发送 GET 请求。\n",
    "2. `response.status_code` 是服务器返回的状态码，200 表示成功。\n",
    "3. `response.text` 是服务器返回的响应内容，通常是字符串。\n",
    "4. 如果响应内容是 JSON 格式，`response.json()` 可以将其解析为 Python 字典。\n",
    "\n",
    "---\n",
    "\n",
    "### **4. GET 请求带参数**\n",
    "\n",
    "有时候需要通过 URL 参数向服务器传递信息。这时我们可以使用 `params` 参数来传递查询参数。\n",
    "\n",
    "#### 示例代码："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "f62bddad-19aa-4fd8-a673-2ca10af228ee",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-09-08T14:52:00.850610Z",
     "start_time": "2024-09-08T14:51:59.293035Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "请求的 URL: https://httpbin.org/get?name=Alice&age=25\n",
      "响应内容: {\n",
      "  \"args\": {\n",
      "    \"age\": \"25\", \n",
      "    \"name\": \"Alice\"\n",
      "  }, \n",
      "  \"headers\": {\n",
      "    \"Accept\": \"*/*\", \n",
      "    \"Accept-Encoding\": \"gzip, deflate, br, zstd\", \n",
      "    \"Host\": \"httpbin.org\", \n",
      "    \"User-Agent\": \"python-requests/2.32.2\", \n",
      "    \"X-Amzn-Trace-Id\": \"Root=1-66ddba10-4c914d7c362a38ce71865ff0\"\n",
      "  }, \n",
      "  \"origin\": \"221.15.159.55\", \n",
      "  \"url\": \"https://httpbin.org/get?name=Alice&age=25\"\n",
      "}\n",
      "\n"
     ]
    }
   ],
   "source": [
    "import requests\n",
    "\n",
    "# 构建查询参数\n",
    "params = {\n",
    "    'name': 'Alice',\n",
    "    'age': 25\n",
    "}\n",
    "\n",
    "# 发送带参数的 GET 请求\n",
    "response = requests.get('https://httpbin.org/get', params=params)\n",
    "\n",
    "# 打印请求的 URL，包含了查询参数\n",
    "print(f'请求的 URL: {response.url}')\n",
    "\n",
    "# 打印返回的响应内容\n",
    "print(f'响应内容: {response.text}')\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5bc1beb8-8c93-4694-ba91-8b641c1c52b9",
   "metadata": {},
   "source": [
    "#### 讲解：\n",
    "\n",
    "1. 使用 `params` 参数将查询字符串附加到 URL 中，例如：`?name=Alice&age=25`。\n",
    "2. `response.url` 可以查看包含查询参数的完整 URL。\n",
    "3. `httpbin.org/get` 会返回服务器接收到的所有参数，便于测试。\n",
    "\n",
    "---\n",
    "\n",
    "### **5. POST 请求**\n",
    "\n",
    "POST 请求用于向服务器提交数据。`httpbin` 提供了一个 `post` 接口用于测试。\n",
    "\n",
    "#### 示例代码："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "6ec4c9bc-67b3-4a91-998e-ca548c15bb6d",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-09-08T14:52:02.708626Z",
     "start_time": "2024-09-08T14:52:00.905127Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "状态码: 200\n",
      "响应内容: {'args': {}, 'data': '', 'files': {}, 'form': {'password': 'test_pass', 'username': 'test_user'}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate, br, zstd', 'Content-Length': '37', 'Content-Type': 'application/x-www-form-urlencoded', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.32.2', 'X-Amzn-Trace-Id': 'Root=1-66ddba11-05b1754c1654443b14266f47'}, 'json': None, 'origin': '221.15.159.55', 'url': 'https://httpbin.org/post'}\n"
     ]
    }
   ],
   "source": [
    "import requests\n",
    "\n",
    "# 要发送的数据\n",
    "data = {\n",
    "    'username': 'test_user',\n",
    "    'password': 'test_pass'\n",
    "}\n",
    "\n",
    "# 发送 POST 请求\n",
    "response = requests.post('https://httpbin.org/post', data=data)\n",
    "\n",
    "# 打印状态码\n",
    "print(f'状态码: {response.status_code}')\n",
    "\n",
    "# 打印返回的 JSON 响应\n",
    "print(f'响应内容: {response.json()}')\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "086a7672-b91b-4ee6-8eee-5977e553a1a8",
   "metadata": {},
   "source": [
    "#### 讲解：\n",
    "\n",
    "1. `requests.post()` 用于发送 POST 请求，提交的数据通过 `data` 参数传递。\n",
    "2. `httpbin.org/post` 会返回服务器接收到的 POST 数据，便于调试。\n",
    "3. 服务器返回的响应通常为 JSON，使用 `.json()` 方法解析。\n",
    "\n",
    "---\n",
    "\n",
    "### **6. 上传文件**\n",
    "\n",
    "可以使用 `requests` 发送文件数据，例如上传文件到服务器。\n",
    "\n",
    "#### 示例代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "c54ea5d6-c5f1-4670-a6b8-342ae2b9390c",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-09-08T14:52:03.638921Z",
     "start_time": "2024-09-08T14:52:02.731923Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "响应内容: {'args': {}, 'data': '', 'files': {'file': '商务数据采集与分析'}, 'form': {}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate, br, zstd', 'Content-Length': '174', 'Content-Type': 'multipart/form-data; boundary=1767426d18cd1c0419b0e904e127c12d', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.32.2', 'X-Amzn-Trace-Id': 'Root=1-66ddba13-47a344753c9b0ef70e56f20a'}, 'json': None, 'origin': '221.15.159.55', 'url': 'https://httpbin.org/post'}\n"
     ]
    }
   ],
   "source": [
    "import requests\n",
    "\n",
    "# 要上传的文件\n",
    "files = {\n",
    "    'file': open('example.txt', 'rb')\n",
    "}\n",
    "\n",
    "# 发送文件上传请求\n",
    "response = requests.post('https://httpbin.org/post', files=files)\n",
    "\n",
    "# 打印返回的响应内容\n",
    "print(f'响应内容: {response.json()}')\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5d3f08fc-5509-41c1-aa5a-e5e1c081e6c1",
   "metadata": {},
   "source": [
    "#### 讲解：\n",
    "\n",
    "1. `files` 参数用于上传文件，文件需要以二进制模式打开（`rb`）。\n",
    "2. `httpbin.org/post` 会返回服务器接收到的文件信息。\n",
    "\n",
    "---\n",
    "\n",
    "### **7. 自定义请求头**\n",
    "\n",
    "有时需要在请求中添加自定义的 HTTP 头，比如 `User-Agent` 或 `Authorization`。\n",
    "\n",
    "#### 示例代码："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "c3d2c815-edd8-43bf-a3a0-a15f89779eef",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-09-08T14:52:04.624681Z",
     "start_time": "2024-09-08T14:52:03.664556Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "响应内容: {\n",
      "  \"args\": {}, \n",
      "  \"headers\": {\n",
      "    \"Accept\": \"*/*\", \n",
      "    \"Accept-Encoding\": \"gzip, deflate, br, zstd\", \n",
      "    \"Host\": \"httpbin.org\", \n",
      "    \"User-Agent\": \"my-app/1.0\", \n",
      "    \"X-Amzn-Trace-Id\": \"Root=1-66ddba14-528210b21d79308c7f92632b\"\n",
      "  }, \n",
      "  \"origin\": \"221.15.159.55\", \n",
      "  \"url\": \"https://httpbin.org/get\"\n",
      "}\n",
      "\n"
     ]
    }
   ],
   "source": [
    "import requests\n",
    "\n",
    "# 自定义 HTTP 头\n",
    "headers = {\n",
    "    'User-Agent': 'my-app/1.0'\n",
    "}\n",
    "\n",
    "# 发送带自定义头的 GET 请求\n",
    "response = requests.get('https://httpbin.org/get', headers=headers)\n",
    "\n",
    "# 打印返回的响应内容\n",
    "print(f'响应内容: {response.text}')\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d951fcdc-bbbf-419a-aaa7-fb8666b3d3d3",
   "metadata": {},
   "source": [
    "#### 讲解：\n",
    "\n",
    "1. `headers` 参数用于添加自定义 HTTP 头。\n",
    "2. 常见的头包括 `User-Agent`（标识客户端）和 `Authorization`（身份认证）。\n",
    "\n",
    "---\n",
    "\n",
    "### **8. 处理异常**\n",
    "\n",
    "在网络请求中，可能会出现连接失败、超时等问题。可以通过捕获异常进行处理。\n",
    "\n",
    "#### 示例代码："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "6f49ab50-ab75-4415-9bfe-88ea019119a8",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-09-08T14:52:10.331080Z",
     "start_time": "2024-09-08T14:52:04.638652Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "请求超时\n"
     ]
    }
   ],
   "source": [
    "import requests\n",
    "\n",
    "try:\n",
    "    # 设置超时时间为 5 秒\n",
    "    response = requests.get('https://httpbin.org/delay/10', timeout=5)\n",
    "    print(f'状态码: {response.status_code}')\n",
    "except requests.Timeout:\n",
    "    print('请求超时')\n",
    "except requests.RequestException as e:\n",
    "    print(f'请求失败: {e}')\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fe0133fa-eaeb-40ef-b738-a8e168b89627",
   "metadata": {},
   "source": [
    "#### 讲解：\n",
    "\n",
    "1. `timeout` 参数用于设置请求超时时间。\n",
    "2. 使用 `try-except` 块捕获异常，例如 `requests.Timeout` 处理超时异常，`requests.RequestException` 处理所有请求相关的异常。\n",
    "\n",
    "---\n",
    "\n",
    "### **9. 会话与 Cookie**\n",
    "\n",
    "`requests.Session` 对象允许你跨多个请求保持某些参数（例如 Cookie）。\n",
    "\n",
    "#### 示例代码："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "e0f85c00-9908-46b4-a45a-41f1fcd9f748",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-09-08T14:52:13.381006Z",
     "start_time": "2024-09-08T14:52:10.354672Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "响应内容: {\n",
      "  \"cookies\": {\n",
      "    \"sessioncookie\": \"123456789\"\n",
      "  }\n",
      "}\n",
      "\n"
     ]
    }
   ],
   "source": [
    "import requests\n",
    "\n",
    "# 创建一个会话对象\n",
    "session = requests.Session()\n",
    "\n",
    "# 发送请求，设置 Cookie\n",
    "session.get('https://httpbin.org/cookies/set/sessioncookie/123456789')\n",
    "\n",
    "# 发送另一个请求，查看 Cookie\n",
    "response = session.get('https://httpbin.org/cookies')\n",
    "\n",
    "# 打印返回的响应内容，查看 Cookie 是否被保留\n",
    "print(f'响应内容: {response.text}')\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e95578db-dd24-4073-bee4-93a709bbf503",
   "metadata": {},
   "source": [
    " `requests` 库get请求实例"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "3e0b1841-b296-4d44-8dbe-7f40be32a8a2",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-09-08T14:52:13.774850Z",
     "start_time": "2024-09-08T14:52:13.471878Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "网页保存成功!\n"
     ]
    }
   ],
   "source": [
    "import requests\n",
    "\n",
    "# 设置请求的 URL\n",
    "url = \"https://movie.douban.com/top250\"\n",
    "\n",
    "# 定义请求头，模拟浏览器\n",
    "headers = {\n",
    "    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'\n",
    "}\n",
    "\n",
    "# 发送 GET 请求\n",
    "response = requests.get(url, headers=headers)\n",
    "\n",
    "# 检查请求是否成功\n",
    "if response.status_code == 200:\n",
    "    # 将网页内容保存到本地文件\n",
    "    with open(\"douban_top250.html\", \"w\", encoding='utf-8') as file:\n",
    "        file.write(response.text)\n",
    "    print(\"网页保存成功!\")\n",
    "else:\n",
    "    print(f\"请求失败，状态码: {response.status_code}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6da44f7b-3776-4160-8889-3f2bccbcd3be",
   "metadata": {},
   "source": [
    "### 代码解释：\n",
    "\n",
    "1. **请求页面**：使用 `requests.get` 向目标 URL 发送 HTTP GET 请求。我们通过设置 `headers` 来模仿浏览器请求，避免被服务器拒绝（有些服务器会限制非浏览器请求）。\n",
    "\n",
    "2. **检查响应状态码**：通过 `response.status_code` 检查请求是否成功，通常状态码为 200 表示成功。\n",
    "\n",
    "3. **保存网页内容**：如果请求成功，我们将通过 `response.text` 获取网页的 HTML 内容，并将其保存到本地文件 `douban_top250.html` 中。使用 `open()` 函数创建文件，并通过 `file.write()` 将内容写入文件。\n",
    "\n",
    "4. **处理错误**：如果请求失败（例如网络问题或服务器错误），程序会打印状态码，方便调试。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "289eac5c-6f29-4c43-a913-086d8021e119",
   "metadata": {},
   "source": [
    "http://localhost:8000/login.html 作为我们服务器网站"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7130425f-51f1-42ee-a7dc-7f1c3ed45509",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "7b65f948-13c4-4865-b554-f19e81a14183",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "登录失败，状态码: 501\n"
     ]
    }
   ],
   "source": [
    "import requests\n",
    "\n",
    "# 创建会话对象，保持会话\n",
    "session = requests.Session()\n",
    "\n",
    "# 定义登录页面和登录后页面的URL\n",
    "login_url = 'http://127.0.0.1:5000/login'\n",
    "home_url = 'http://127.0.0.1:5000/'\n",
    "\n",
    "# 定义登录表单数据\n",
    "login_data = {\n",
    "    'username': 'zcfe',  # 用户名\n",
    "    'password': '123456'  # 密码\n",
    "}\n",
    "\n",
    "# 第一步：获取登录页面\n",
    "response = session.get(home_url)\n",
    "\n",
    "# 检查登录页面请求是否成功\n",
    "if response.status_code == 200:\n",
    "    print(\"成功访问登录页面\")\n",
    "\n",
    "    # 第二步：发送 POST 请求，提交登录表单\n",
    "    login_response = session.post(login_url, data=login_data)\n",
    "\n",
    "    # 检查是否登录成功\n",
    "    if login_response.status_code == 200:\n",
    "        print(\"登录成功\")\n",
    "\n",
    "        # 第三步：保存登录后的页面\n",
    "        with open('logged_in_page.html', 'w', encoding='utf-8') as file:\n",
    "            file.write(login_response.text)\n",
    "\n",
    "        print(\"登录后的页面已保存为 'logged_in_page.html'\")\n",
    "    else:\n",
    "        print(f\"登录失败，状态码: {login_response.status_code}\")\n",
    "else:\n",
    "    print(f\"无法访问登录页面，状态码: {response.status_code}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b83185fc-7633-4ab2-9c46-d5f9833dd2b9",
   "metadata": {},
   "source": [
    "#### 1. 什么是 API？\n",
    "\n",
    "API（**应用程序编程接口**）是一种让两个程序通过网络互相通信的工具。它规定了你可以如何向服务器请求数据，服务器如何给你响应。\n",
    "\n",
    "- **通俗理解**：API 就像一家餐馆里的服务员。你告诉服务员你想吃什么（发送请求），服务员会按照你的要求把菜送到你面前（返回响应）。\n",
    "- **请求**：你需要遵循 API 规定的格式告诉服务器你需要什么数据。\n",
    "- **响应**：服务器会按照定义好的格式把你想要的数据返回给你。\n",
    "\n",
    "#### 2. 为什么 API 很重要？\n",
    "\n",
    "API 提供了一种快速、可靠的方式获取结构化的数据。比如，如果你想获取股票价格、天气预报、或地图信息，API 会比从网页上手动抓取信息（爬虫）更方便。\n",
    "\n",
    "#### 3. API 是如何工作的？\n",
    "\n",
    "- **客户端发送请求**：你按照 API 的规定格式发送请求（比如一个网址），带上必要的参数（像城市代码或股票代码）。\n",
    "- **服务器返回响应**：API 服务器处理请求并返回数据，这些数据一般是结构化的，比如 JSON 格式。\n",
    "\n",
    "  - **请求**：客户端发送请求，说明想要什么数据。\n",
    "  - **响应**：服务器返回指定格式的响应，包含客户端想要的数据。\n",
    "\n",
    "#### 4. API 和爬虫有什么区别？\n",
    "\n",
    "- **API**：API 是按照规定格式直接请求数据，服务器会给你整理好、格式化的数据。API 的数据通常是经过优化，响应更快、数据结构清晰。\n",
    "- **爬虫**：爬虫是通过抓取网页 HTML 代码并解析其中的数据。这种方式虽然可以获取数据，但数据格式杂乱，可能需要手动提取和清理。\n",
    "\n",
    "#### 5. 为什么大部分 API 是收费的？\n",
    "\n",
    "服务器提供 API 服务通常是收费的，因为：\n",
    "\n",
    "- **服务器资源成本**：API 提供的服务通常需要大量的计算和存储资源。\n",
    "- **数据整理成本**：API 提供的是已经整理好、结构化的数据，节省了你自己从网页抓取和整理数据的时间。\n",
    "- **服务质量**：收费的 API 通常提供更高的可靠性、稳定性和技术支持。\n",
    "\n",
    "#### 6. 实际例子：天气 API\n",
    "\n",
    "假设我们要获取郑州市的天气数据。API 提供了一个接口，你只需要提供郑州市的城市代码，API 就会给你返回该城市的天气数据。\n",
    "\n",
    "##### 请求格式：\n",
    "\n",
    "```\n",
    "http://t.weather.itboy.net/api/weather/city/101180101\n",
    "```\n",
    "\n",
    "- **请求内容**：城市代码（如：101180101 为郑州的城市代码）。\n",
    "- **响应内容**：包含该城市的当前温度、湿度、空气质量、未来天气等。\n",
    "\n",
    "##### Python 示例代码："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "38837b93-d00f-4c97-a801-ee8344cce246",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'message': 'success感谢又拍云(upyun.com)提供CDN赞助', 'status': 200, 'date': '20240923', 'time': '2024-09-24 00:44:44', 'cityInfo': {'city': '郑州市', 'citykey': '101180101', 'parent': '河南', 'updateTime': '21:14'}, 'data': {'shidu': '51%', 'pm25': 28.0, 'pm10': 52.0, 'quality': '良', 'wendu': '19.5', 'ganmao': '极少数敏感人群应减少户外活动', 'forecast': [{'date': '23', 'high': '高温 24℃', 'low': '低温 13℃', 'ymd': '2024-09-23', 'week': '星期一', 'sunrise': '06:14', 'sunset': '18:21', 'aqi': 41, 'fx': '东南风', 'fl': '2级', 'type': '多云', 'notice': '阴晴之间，谨防紫外线侵扰'}, {'date': '24', 'high': '高温 26℃', 'low': '低温 13℃', 'ymd': '2024-09-24', 'week': '星期二', 'sunrise': '06:15', 'sunset': '18:19', 'aqi': 64, 'fx': '南风', 'fl': '2级', 'type': '晴', 'notice': '愿你拥有比阳光明媚的心情'}, {'date': '25', 'high': '高温 28℃', 'low': '低温 16℃', 'ymd': '2024-09-25', 'week': '星期三', 'sunrise': '06:15', 'sunset': '18:18', 'aqi': 76, 'fx': '东南风', 'fl': '2级', 'type': '晴', 'notice': '愿你拥有比阳光明媚的心情'}, {'date': '26', 'high': '高温 26℃', 'low': '低温 18℃', 'ymd': '2024-09-26', 'week': '星期四', 'sunrise': '06:16', 'sunset': '18:16', 'aqi': 87, 'fx': '东风', 'fl': '2级', 'type': '阴', 'notice': '不要被阴云遮挡住好心情'}, {'date': '27', 'high': '高温 28℃', 'low': '低温 17℃', 'ymd': '2024-09-27', 'week': '星期五', 'sunrise': '06:17', 'sunset': '18:15', 'aqi': 83, 'fx': '东南风', 'fl': '2级', 'type': '多云', 'notice': '阴晴之间，谨防紫外线侵扰'}, {'date': '28', 'high': '高温 27℃', 'low': '低温 19℃', 'ymd': '2024-09-28', 'week': '星期六', 'sunrise': '06:18', 'sunset': '18:14', 'aqi': 76, 'fx': '东南风', 'fl': '3级', 'type': '阴', 'notice': '不要被阴云遮挡住好心情'}, {'date': '29', 'high': '高温 28℃', 'low': '低温 18℃', 'ymd': '2024-09-29', 'week': '星期日', 'sunrise': '06:18', 'sunset': '18:12', 'aqi': 78, 'fx': '西北风', 'fl': '3级', 'type': '大雨', 'notice': '出门最好穿雨衣，勿挡视线'}, {'date': '30', 'high': '高温 18℃', 'low': '低温 13℃', 'ymd': '2024-09-30', 'week': '星期一', 'sunrise': '06:19', 'sunset': '18:11', 'aqi': 78, 'fx': '东北风', 'fl': '3级', 'type': '阴', 'notice': '不要被阴云遮挡住好心情'}, {'date': '01', 'high': '高温 15℃', 'low': '低温 12℃', 'ymd': '2024-10-01', 'week': '星期二', 'sunrise': '06:20', 'sunset': '18:09', 'aqi': 86, 'fx': '东风', 'fl': '1级', 'type': '阴', 'notice': '不要被阴云遮挡住好心情'}, {'date': '02', 'high': '高温 22℃', 'low': '低温 12℃', 'ymd': '2024-10-02', 'week': '星期三', 'sunrise': '06:21', 'sunset': '18:08', 'aqi': 94, 'fx': '南风', 'fl': '2级', 'type': '多云', 'notice': '阴晴之间，谨防紫外线侵扰'}, {'date': '03', 'high': '高温 27℃', 'low': '低温 16℃', 'ymd': '2024-10-03', 'week': '星期四', 'sunrise': '06:21', 'sunset': '18:07', 'aqi': 92, 'fx': '西南风', 'fl': '1级', 'type': '晴', 'notice': '愿你拥有比阳光明媚的心情'}, {'date': '04', 'high': '高温 25℃', 'low': '低温 17℃', 'ymd': '2024-10-04', 'week': '星期五', 'sunrise': '06:22', 'sunset': '18:05', 'aqi': 76, 'fx': '东南风', 'fl': '2级', 'type': '阴', 'notice': '不要被阴云遮挡住好心情'}, {'date': '05', 'high': '高温 25℃', 'low': '低温 19℃', 'ymd': '2024-10-05', 'week': '星期六', 'sunrise': '06:23', 'sunset': '18:04', 'aqi': 80, 'fx': '东南风', 'fl': '2级', 'type': '阴', 'notice': '不要被阴云遮挡住好心情'}, {'date': '06', 'high': '高温 19℃', 'low': '低温 16℃', 'ymd': '2024-10-06', 'week': '星期日', 'sunrise': '06:24', 'sunset': '18:02', 'aqi': 82, 'fx': '西北风', 'fl': '2级', 'type': '中雨', 'notice': '记得随身携带雨伞哦'}, {'date': '07', 'high': '高温 20℃', 'low': '低温 14℃', 'ymd': '2024-10-07', 'week': '星期一', 'sunrise': '06:24', 'sunset': '18:01', 'aqi': 32, 'fx': '东北风', 'fl': '2级', 'type': '阴', 'notice': '不要被阴云遮挡住好心情'}], 'yesterday': {'date': '22', 'high': '高温 24℃', 'low': '低温 14℃', 'ymd': '2024-09-22', 'week': '星期日', 'sunrise': '06:13', 'sunset': '18:22', 'aqi': 28, 'fx': '东北风', 'fl': '2级', 'type': '晴', 'notice': '愿你拥有比阳光明媚的心情'}}}\n"
     ]
    }
   ],
   "source": [
    "import requests\n",
    "\n",
    "def fetch_weather_data(city_code):\n",
    "    url = f\"http://t.weather.itboy.net/api/weather/city/{city_code}\"\n",
    "    response = requests.get(url)\n",
    "    if response.status_code == 200:\n",
    "        return response.json()\n",
    "    else:\n",
    "        return None\n",
    "\n",
    "# 获取郑州天气信息\n",
    "city_code = '101180101'\n",
    "weather_data = fetch_weather_data(city_code)\n",
    "print(weather_data)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "54f7e776-0091-4a42-b430-b020b2f9b479",
   "metadata": {},
   "source": [
    "练习题目：通过 API 获取天气预报数据 目的： 本次练习的目标是帮助学生熟悉如何使用 Python 中的 requests 库与 API 进行交互，学习解析 JSON 格式的数据，并将提取出的信息以结构化的方式展示给用户。\n",
    "\n",
    "要求： 编写一个 Python 脚本，通过访问天气预报 API 来获取指定城市的天气数据。学生可以使用 中国天气网 提供的不同城市代码来查询对应城市的天气情况。\n",
    "\n",
    "代码中需要完成以下功能：\n",
    "\n",
    "向 http://t.weather.itboy.net/api/weather/city/{city_code} 发送 GET 请求，其中 {city_code} 为城市代码。 提取并展示以下信息： 当前城市及其天气更新时间。 当前的温度、湿度、空气质量、感冒提醒等。 未来几天的天气预报，包括日期、天气类型（如晴、阴、雨等）、温度范围、风向、空气质量指数、以及其他天气提醒。 昨天的天气情况，类似未来几天的预报内容。 程序中需要处理网络请求失败或无法获取天气数据的情况，给用户输出友好的提示信息。\n",
    "\n",
    "学生可以从 中国天气网 https://www.weather.com.cn/weather1d/101180101.shtml中选择不同城市的代码，替换示例代码中的 city_code 参数，查看其他城市的天气情况。常见城市的代码可以通过查看网页地址中的数字获取，如：\n",
    "\n",
    "北京：101010100 上海：101020100 广州：101280101 郑州：101180101 代码示例： 可以参考如下 Python 代码示例，并根据需求进行修改："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "eee6a8da-2375-4625-b2b0-ff1b2d364220",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "天气预报城市：郑州市\n",
      "更新时间：21:14\n",
      "当前温度：19.5℃，湿度：51%，空气质量：良。极少数敏感人群应减少户外活动\n",
      "\n",
      "未来几天的天气预报：\n",
      "23日(星期一), 2024-09-23\n",
      "    多云, 低温 13℃到高温 24℃, 风向：东南风 2级, 空气质量指数：41\n",
      "    阴晴之间，谨防紫外线侵扰\n",
      "\n",
      "24日(星期二), 2024-09-24\n",
      "    晴, 低温 13℃到高温 26℃, 风向：南风 2级, 空气质量指数：64\n",
      "    愿你拥有比阳光明媚的心情\n",
      "\n",
      "25日(星期三), 2024-09-25\n",
      "    晴, 低温 16℃到高温 28℃, 风向：东南风 2级, 空气质量指数：76\n",
      "    愿你拥有比阳光明媚的心情\n",
      "\n",
      "26日(星期四), 2024-09-26\n",
      "    阴, 低温 18℃到高温 26℃, 风向：东风 2级, 空气质量指数：87\n",
      "    不要被阴云遮挡住好心情\n",
      "\n",
      "27日(星期五), 2024-09-27\n",
      "    多云, 低温 17℃到高温 28℃, 风向：东南风 2级, 空气质量指数：83\n",
      "    阴晴之间，谨防紫外线侵扰\n",
      "\n",
      "28日(星期六), 2024-09-28\n",
      "    阴, 低温 19℃到高温 27℃, 风向：东南风 3级, 空气质量指数：76\n",
      "    不要被阴云遮挡住好心情\n",
      "\n",
      "29日(星期日), 2024-09-29\n",
      "    大雨, 低温 18℃到高温 28℃, 风向：西北风 3级, 空气质量指数：78\n",
      "    出门最好穿雨衣，勿挡视线\n",
      "\n",
      "30日(星期一), 2024-09-30\n",
      "    阴, 低温 13℃到高温 18℃, 风向：东北风 3级, 空气质量指数：78\n",
      "    不要被阴云遮挡住好心情\n",
      "\n",
      "01日(星期二), 2024-10-01\n",
      "    阴, 低温 12℃到高温 15℃, 风向：东风 1级, 空气质量指数：86\n",
      "    不要被阴云遮挡住好心情\n",
      "\n",
      "02日(星期三), 2024-10-02\n",
      "    多云, 低温 12℃到高温 22℃, 风向：南风 2级, 空气质量指数：94\n",
      "    阴晴之间，谨防紫外线侵扰\n",
      "\n",
      "03日(星期四), 2024-10-03\n",
      "    晴, 低温 16℃到高温 27℃, 风向：西南风 1级, 空气质量指数：92\n",
      "    愿你拥有比阳光明媚的心情\n",
      "\n",
      "04日(星期五), 2024-10-04\n",
      "    阴, 低温 17℃到高温 25℃, 风向：东南风 2级, 空气质量指数：76\n",
      "    不要被阴云遮挡住好心情\n",
      "\n",
      "05日(星期六), 2024-10-05\n",
      "    阴, 低温 19℃到高温 25℃, 风向：东南风 2级, 空气质量指数：80\n",
      "    不要被阴云遮挡住好心情\n",
      "\n",
      "06日(星期日), 2024-10-06\n",
      "    中雨, 低温 16℃到高温 19℃, 风向：西北风 2级, 空气质量指数：82\n",
      "    记得随身携带雨伞哦\n",
      "\n",
      "07日(星期一), 2024-10-07\n",
      "    阴, 低温 14℃到高温 20℃, 风向：东北风 2级, 空气质量指数：32\n",
      "    不要被阴云遮挡住好心情\n",
      "\n",
      "昨日天气：\n",
      "22日(星期日), 2024-09-22\n",
      "    晴, 低温 14℃到高温 24℃, 风向：东北风 2级, 空气质量指数：28\n",
      "    愿你拥有比阳光明媚的心情\n",
      "\n"
     ]
    }
   ],
   "source": [
    "import requests\n",
    "\n",
    "def fetch_weather_data(city_code):\n",
    "    url = f\"http://t.weather.itboy.net/api/weather/city/{city_code}\"\n",
    "    try:\n",
    "        response = requests.get(url)\n",
    "        if response.status_code != 200:\n",
    "            raise Exception(f\"HTTP error! status: {response.status_code}\")\n",
    "        return response.json()\n",
    "    except Exception as error:\n",
    "        print('Could not fetch weather data:', error)\n",
    "        return None\n",
    "\n",
    "def print_weather_forecast(city_code):\n",
    "    weather_data = fetch_weather_data(city_code)\n",
    "    if not weather_data:\n",
    "        print(\"No weather data available.\")\n",
    "        return\n",
    "\n",
    "    city_info = weather_data['cityInfo']\n",
    "    city = city_info['city']\n",
    "    print(f\"天气预报城市：{city}\\n更新时间：{city_info['updateTime']}\")\n",
    "\n",
    "    data = weather_data['data']\n",
    "    print(f\"当前温度：{data['wendu']}℃，湿度：{data['shidu']}，空气质量：{data['quality']}。{data['ganmao']}\\n\")\n",
    "\n",
    "    forecast = data['forecast']\n",
    "    print(\"未来几天的天气预报：\")\n",
    "    for day in forecast:\n",
    "        print(f\"{day['date']}日({day['week']}), {day['ymd']}\")\n",
    "        print(f\"    {day['type']}, {day['low']}到{day['high']}, 风向：{day['fx']} {day['fl']}, 空气质量指数：{day['aqi']}\")\n",
    "        print(f\"    {day['notice']}\\n\")\n",
    "\n",
    "    yesterday = data['yesterday']\n",
    "    print(\"昨日天气：\")\n",
    "    print(f\"{yesterday['date']}日({yesterday['week']}), {yesterday['ymd']}\")\n",
    "    print(f\"    {yesterday['type']}, {yesterday['low']}到{yesterday['high']}, 风向：{yesterday['fx']} {yesterday['fl']}, 空气质量指数：{yesterday['aqi']}\")\n",
    "    print(f\"    {yesterday['notice']}\\n\")\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    city_code = '101180101'  # 示例：郑州市的城市代码\n",
    "    print_weather_forecast(city_code)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1663eb78-478d-44b7-8c69-43639059dd8d",
   "metadata": {},
   "source": [
    "理解 API 请求与响应的基本流程。\n",
    "选一个免费 API（例如天气 API 或股票 API），编写 Python 程序，获取并展示你想要的特定数据。\n",
    "示例：选择一个城市，通过天气 API 获取该城市的天气信息，并在控制台展示温度、湿度等数据。\n",
    "思考 API 的优势：为什么用 API 比直接从网页抓取数据（爬虫）更有效？"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e85da23d-3a55-4a40-ad6c-09d1c83372c0",
   "metadata": {},
   "source": [
    "https://www.juhe.cn/ 一个api集合"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bcd7767c-4869-4e30-a8c0-7afa62a8bd93",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
